home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # Apple Developer Technical Support
- #
- # AppleEvent Sample Control Panel Device
- #
- # AECDEV
- #
- # AECDEV.c - C Source
- # Written by C.K. Haun
- #
- # Copyright © 1991 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions: 1.0 8/91
- #
- # Components: AECdev.p August 2, 1991
- # AECDEV.PPC.c August 2, 1991
- #
- # AECDEV demonstrates the techniques needed to send AppleEvents
- # from a CDEV/DA/INIT/Driver.
- # Requires the sample AEDaemon to work.
- #
- ------------------------------------------------------------------------------*/
- /*------------------------------------------------------------------------------
- # This file contains the AppleEvent code that creates the
- # AppleEvent, and PPC toolbox code that finds and transfers the data to the
- # Backgrounder.
- # It also contains the PBCatSearch code.
- ------------------------------------------------------------------------------*/
-
- #include "AECdev.h"
- /* FindATarget prompts the user for a target application (through the PPC browser) */
- /* and a document for that application to open (with Standard File) */
- /* Once it's gotten that information, it bundles up the information about the */
- /* document to be opened into an APpleEvent list, adds the address of the target */
- /* application to the event, and passes the data to the routine that starts the PPC */
- /* transfer */
- void FindATarget(CDEVHnd storage)
- {
- OSErr theErr = noErr;
- LocationNameRec theLoc;
- PortInfoRec theRec;
- AEDesc theAddress, docDesc;
- AEDescList theList;
- AliasHandle myAlias;
- StandardFileReply myReply;
- TargetID theID;
- AppleEvent theEvent;
- Str32 tWext;
- Str32 txWext;
- /* Get the strings that will appear in the PPC browser */
- GetIndString(&tWext, kStringsID, kBrowse1);
- GetIndString(&txWext, kStringsID, kBrowse2);
- /* Choose the Application you want to send the event to */
- if (noErr == PPCBrowser(tWext, &txWext, false, &theLoc, &theRec, nil, nil)) {
- /* Now I'll create the ODOC applevent */
- /* Create the targetID for the selected application first */
- theID.name = theRec.name;
- theID.location = theLoc;
- theErr = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), &theAddress);
- if (theErr == noErr) {
- /* Create the whole event */
- theErr = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &theAddress, kAutoGenerateReturnID, kAnyTransactionID,
- &theEvent);
- if (theErr == noErr) {
- /* now get a document to pass */
- StandardGetFile(nil, -1, nil, &myReply);
- if (myReply.sfGood) {
- /* odoc passed a list of FSSpecs, so make a list */
- /* even though this will only contain one spec, you still need a list */
- theErr = AECreateList(nil, 0, false, &theList);
- if (theErr == noErr) {
- /* create an alias out of the file spec */
- /* I'm not real sure why I did this, since there is a system coercion handler for */
- /* alias to FSSpec, but I'm paranoid (and goofy) */
- theErr = NewAlias(nil, &myReply.sfFile, &myAlias);
- if (theErr == noErr) {
- HLock((Handle)myAlias);
- /* now create an alias descriptor */
- theErr = AECreateDesc(typeAlias, (Ptr)*myAlias, GetHandleSize((Handle)myAlias), &docDesc);
- if (theErr == noErr) {
- DisposHandle((Handle)myAlias); /* no longer needed */
- /* put it in the list */
- theErr = AEPutDesc(&theList, 0, &docDesc);
- if (theErr == noErr) {
- /* and put the list in the event */
- theErr = AEPutParamDesc(&theEvent, keyDirectObject, &theList);
- if (theErr == noErr) {
- /* now I'm passing the data portion of the AppleEvent to the handler */
- /* that will open a PPC channel and pass the information along */
- FireTheEvent(theEvent.dataHandle, storage);
- } /* putparamdesc err */
- } /* putDesc error */
- /* dispose of all the appleevent strutures I've been using */
- AEDisposeDesc(&docDesc);
- } /* docDesc creation error */
- } /* alias creation error */
- AEDisposeDesc(&theList);
- } /* list create error */
-
- } /* standardfile cancel */
- AEDisposeDesc(&theEvent);
- } /* event create error */
- AEDisposeDesc(&theAddress);
- } /* desc 1 error */
- } /* browser cancel or error */
- } /* end FindATarget */
-
- /* FindAEBuddy searches for the port to use to send the event. In this */
- /* case I'm using my AEDaemon application to send events for me. */
- /* So, if first see if it's available by looking for it's port with */
- /* IPCListPorts. If it isn't available, I search for it by */
- /* creator and file type with PBCatSearch, and launch it if I find it */
- /* Of course, if I launch it myself I need to give it some time */
- /* to register itself and come up in the PPC port list, so I'll set */
- /* a flag and go away for a while, checking back periodically until */
- /* the port comes up */
- /* You can use AEBuddy also for your app, though I'd change the name.... */
- void FindAEBuddy(CDEVHnd storage)
- {
- Byte csState;
- CDEVPtr tempPtr;
- CursHandle watch;
- /* Use NewPtrClear for these, so you don't have to worry about having */
- /* garbage in the parameters to start */
- IPCListPortsPBPtr listPtr = NewPtrClear(sizeof(IPCListPortsPBRec));
- PPCPortPtr portWanted = NewPtrClear(sizeof(PPCPortRec));
- LaunchParamBlockRec launchThis;
- short realCount;
- OSErr myError;
- /* find AEBuddy, open our port, and pass the data */
- /* remember NewPtrClear gave me a zeroed record, so all the parameters */
- /* that I wanted nil'ed are. */
- /* BY THE WAY: I could use the PPCBrowser again here, of course. */
- /* but remember, most of your users will have no idea that this CDEV is */
- /* using another process, since faceless backgrounders don't show up */
- /* in any list that most users can see */
- watch = GetCursor(watchCursor);
- SetCursor(*watch); /* wait cursor */
- csState = HGetState((Handle)storage);
- HLock((Handle)storage);
- tempPtr = *storage; /* dereference this for clarity */
- listPtr->requestCount = 1; /* only want one of them */
- listPtr->portName = portWanted;
- /* fill in the port a bit */
- portWanted->name[0] = 1; /* making a "=" string here, telling IPCListPorts */
- portWanted->name[1] = '='; /* that I don't care about the name of the port */
- portWanted->portKindSelector = ppcByCreatorAndType;
- portWanted->u.port.creator = 'MOOB';
- portWanted->u.port.type = 'APPL';
- /* the location name will be nil, since I want to get the thing on the */
- /* local machine, not across the vast net */
- listPtr->locationName = nil;
- listPtr->bufferPtr = (PortInfoArrayPtr)NewPtrClear(sizeof(PortInfoRec));
- /* we're only asking for one, so we only need one array space allocated */
-
- myError = IPCListPorts(listPtr, false); /* getting it syncronously */
- realCount = listPtr->actualCount;
- /* so we don't forget */
- if (myError == noErr) {
- if (realCount == 0 && (*storage)->searchForTarget == false) {
- /* The following segment is the PBCatSearch area */
-
- /* Couldn't find the port and we haven't launched it ourselves yet. */
- /* So, let's see if we can find the app and launch it */
- /* ourselves */
- /* make a pointer to the block */
- CSParamPtr csBlockPtr = NewPtrClear(sizeof(CSParam));
- long dirIDUnused;
- Str32 nulString = "\p";
- /* initialize the parameter block */
- if (csBlockPtr) {
- csBlockPtr->ioSearchInfo1 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
- csBlockPtr->ioSearchInfo2 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
- if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2) {
- csBlockPtr->ioMatchPtr = (FSSpecPtr)NewPtrClear(sizeof(FSSpec) * 1); /* only looking for 1 */
- if (csBlockPtr->ioMatchPtr) {
- /* Now see if we can create an optimization buffer */
- csBlockPtr->ioOptBuffer = NewPtr(2048);
- if (csBlockPtr->ioOptBuffer)
- csBlockPtr->ioOptBufSize = 2048;
- else
- csBlockPtr->ioOptBufSize = 0; /* no buffer, sorry */
- csBlockPtr->ioReqMatchCount = 1;
- csBlockPtr->ioSearchTime = 0; /* no timeout */
- }
- }
- }
- /* check all my memory allocations here */
- if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2 && csBlockPtr->ioMatchPtr) {
- /* had memory, continue */
- HGetVol(nil, &csBlockPtr->ioVRefNum, &dirIDUnused); /* get default volume for search */
- csBlockPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
- csBlockPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
- csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = 'MOOB';
- csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = 'APPL';
- csBlockPtr->ioSearchBits = fsSBFlFndrInfo;
- csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
- csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
- myError = PBCatSearch(csBlockPtr, false); /* search sync */
- if (myError == noErr && csBlockPtr->ioActMatchCount != 0) {
-
- /* we found it, so launch it */
- launchThis.launchBlockID = extendedBlock;
- launchThis.launchEPBLength = extendedBlockLen;
- launchThis.launchFileFlags = nil;
- launchThis.launchControlFlags = launchContinue + launchNoFileFlags;
- launchThis.launchAppSpec = &csBlockPtr->ioMatchPtr[0];
- myError = LaunchApplication(&launchThis);
- if (myError == noErr) {
- /* it launched fine. Set a flag so we can */
- /* check periodically until it's */
- /* PPC port comes up */
- (*storage)->searchForTarget = true;
- }
- } else {
- /* PBCat failed, we have no buddy on this volume. Oh well */
- (*storage)->noBuddy = true;
- }
- } /* out of memory error */
- if (csBlockPtr) {
- /* clean up what we allocated */
- if (csBlockPtr->ioSearchInfo1)
- DisposPtr((Ptr)csBlockPtr->ioSearchInfo1);
- if (csBlockPtr->ioSearchInfo2)
- DisposPtr((Ptr)csBlockPtr->ioSearchInfo2);
- if (csBlockPtr->ioMatchPtr)
- DisposPtr((Ptr)csBlockPtr->ioMatchPtr);
- if (csBlockPtr->ioOptBuffer)
- DisposPtr((Ptr)csBlockPtr->ioOptBuffer);
- DisposPtr((Ptr)csBlockPtr);
- }
-
- /* catsearch section end */
- } else {
- PortInfoPtr portInfoTemp = (PortInfoPtr)listPtr->bufferPtr;
- tempPtr->myPPCBlock->buddyPortPtr = (PPCPortPtr)NewPtrClear(sizeof(PPCPortRec));
- /* we have a port to send to. So, we'll first clear that flag... */
- (*storage)->searchForTarget = false;
- BlockMove((Ptr)&portInfoTemp->name, (Ptr)tempPtr->myPPCBlock->buddyPortPtr, sizeof(PPCPortRec));
-
- }
- } /* listports err */
- /* clean up the IPCListPorts memory */
- if (listPtr->bufferPtr)
- DisposPtr((Ptr)listPtr->bufferPtr);
- if (listPtr)
- DisposPtr((Ptr)listPtr);
- if (portWanted)
- DisposPtr((Ptr)portWanted);
-
- /* NOTE: I don't need to clean up listPtr->bufferPtr since I moved this into */
- /* our other structure for later use */
- InitCursor();
- } /* end FindAEBuddy */
-
- /* FireTheEvent starts the PPC process. It opens a port for us, and connects us to */
- /* AEBuddy. The, through a series of asyncronous PPC calls, it transfers all the data */
- /* that makes up the APpleEvent we want to send. */
- void FireTheEvent(Handle packedEvent, CDEVHnd storage)
- {
- /* all this will happen asyncronously, so no error back from this routine */
- /* The first thing we do is open our own port, that completion routine will */
- /* start a session with our target, that completion routine will write the data, */
- /* that completion roiutine will end the session, then that completion routine */
- /* will close the port. */
- /* Open our port */
- /* first check to see if we've already opened a port. If not, open one */
-
- Str32 myName;
- PPCPortPtr myPort = (*storage)->myPPCBlock->myPort;
- PPCOpenPBPtr openPtr = (PPCOpenPBPtr)(*storage)->myPPCBlock;
- /* and once more, local 4 byte space is cheap */
- MyPPCRecPtr ourPtr = (MyPPCRecPtr)openPtr;
- GetIndString(&myName, kStringsID, kMyName);
- /* take the passed handle, make it our own ptr */
- ourPtr->bufferSize = GetHandleSize(packedEvent);
- ourPtr->buffer = NewPtr(GetHandleSize(packedEvent));
- HLock(packedEvent);
- BlockMove((Ptr)*packedEvent, ourPtr->buffer, GetHandleSize(packedEvent));
- /* Create our port */
- myPort->nameScript = 0;
- BlockMove((Ptr)&myName, (Ptr)&myPort->name, myName[0] + 1);
- myPort->portKindSelector = ppcByCreatorAndType;
- myPort->u.port.creator = 'ckh1';
- myPort->u.port.type = 'APPL';
- openPtr->ioCompletion = (PPCCompProcPtr)OpenComplete;
-
- openPtr->serviceType = ppcServiceRealTime; /* only valid one under 7.0 */
- openPtr->resFlag = 0;
- openPtr->portName = myPort;
- openPtr->locationName = nil;
- openPtr->networkVisible = false;
- PPCOpen(openPtr, true);
- (*storage)->eventPending = true;
- }
-
- void OpenComplete(PPCStartPBPtr p)
- {
- OSErr myErr;
- /* cast this so it's easier to see */
- MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
- myErr = p->ioResult;
- if (myErr == noErr) {
- ourPtr->ourPort = p->portRefNum;
- /* We opened our port successfully, so now connect to the buddy */
- p->ioCompletion = (PPCCompProcPtr)StartComplete;
- p->portName = ourPtr->buddyPortPtr;
- p->locationName = nil;
- PPCStart((PPCStartPBPtr)p, true);
- } else {
- DebugStr("\p error in opencomp");
- }
- }
-
- void StartComplete(PPCWritePBPtr p)
- {
- OSErr fred;
- MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
- fred = p->ioResult;
- if (fred == noErr) {
- /* we started a session. In this case, we were allowed to connect without authentication */
- /* so we can start blasting data now */
- p->bufferLength = ourPtr->bufferSize;
- p->bufferPtr = ourPtr->buffer;
- p->more = false;
- /* pass ???? as the creator, the AEBuddy doesn't care who is sending it data */
- p->blockCreator = kGenericCreator;
- /* telling the buddy what type of data I'm sending */
- /* since it _only_ accepts one type */
- p->blockType = kMyTypeOfData;
- p->ioCompletion = (PPCCompProcPtr)WriteComplete;
- ourPtr->currentSessionRef = p->sessRefNum;
- PPCWrite((PPCWritePBPtr)p, (Boolean)true);
- } else {
- DebugStr("\p error in startcomp");
- p->ioCompletion = (PPCCompProcPtr)EndComplete;
- PPCEnd((PPCEndPBPtr)p, true);
-
- }
- }
-
- void WriteComplete(PPCEndPBPtr p)
- {
- MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
- OSErr fred;
- fred = p->ioResult;
- if (fred == noErr) {
- /* We wrote everything we wanted to, time to end the session */
- p->ioCompletion = (PPCCompProcPtr)EndComplete;
- PPCEnd(p, true);
- } else {
- DebugStr("\p error in writecomp");
- p->ioCompletion = (PPCCompProcPtr)EndComplete;
- PPCEnd(p, true);
-
- }
- }
-
- void EndComplete(PPCClosePBPtr p)
- {
- MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
- /* clear our session ref number please */
- if (p->ioResult) {
- DebugStr("\p error in endcomp");
- }
- /* I'm closing our port here, you could of course leave it open */
- /* for repeated requests. One reason why I'm not leaving it open is */
- /* because I don't want anyone to try and talk to us */
- ourPtr->currentSessionRef = nil;
- /* and close the session out */
- p->ioCompletion = nil;
- PPCClose(p, false);
- ourPtr->pB.openParam.portRefNum = nil;
- }
-
-
- #undef __BUILDINGCDEV__
-